import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'test flutter message channel',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const ContactPage(),
    );
  }
}

class ContactDetails {
  ContactDetails({
    required this.name,
    required this.phone,
  });

  final String name;
  final String phone;

  factory ContactDetails.fromMap(Map<String, dynamic> map) => ContactDetails(
    name: map['name'] as String,
    phone: map['phone'] as String,
  );

  Map<String, String> toJson() => <String, String>{
    'name': name,
    'phone': phone,
  };
}

class ContactListModel {
  ContactListModel({
    required this.contactList,
  });

  final List<ContactDetails> contactList;

  factory ContactListModel.fromJson(String jsonString) {
    final jsonData = json.decode(jsonString) as Map<String, dynamic>;
    return ContactListModel(
      contactList: List.from((jsonData['contacts'] as List).map<ContactDetails>(
            (dynamic contactDetailsMap) => ContactDetails.fromMap(
          contactDetailsMap as Map<String, dynamic>,
        ),
      )),
    );
  }

  String toJson() {
    String json = jsonEncode(contactList.map((i) => i.toJson()).toList()).toString();
    return json;
  }
}

class ContactsMessageChannel {
  static const MethodChannel _methodChannel = MethodChannel('methodChannelDemo');

  static const _jsonMessageCodecChannel =
  BasicMessageChannel<dynamic>('jsonMessageCodecDemo', JSONMessageCodec());

  static void addContactDetails(ContactDetails contactDetails) {
    _jsonMessageCodecChannel.send(contactDetails.toJson());
  }

  static Future<ContactListModel> getContacts(String type) async {
    final reply = await _jsonMessageCodecChannel.send('getContact$type');
    if (reply == null) {
      throw PlatformException(
        code: 'INVALID',
        message: 'Failed to get contact',
        details: null,
      );
    } else {
      return ContactListModel.fromJson(reply);
    }
  }

  static Future<int> setContacts(json, String type) async {
    final result = await _methodChannel .invokeMethod<int>('setContacts$type', {'contacts': json});
    return result!;
  }
}

class ContactPage extends StatefulWidget {
  const ContactPage({super.key});

  @override
  State<ContactPage> createState() => _ContactPageState();
}

class _ContactPageState extends State<ContactPage> {
  static const int invokeCount = 1000;

  ContactListModel contactListModel = ContactListModel(contactList: []);

  String dataType = '1000';
  String dataTypeText = '1';

  int getCount = 0;
  int getSetCount = 0;
  final List<String> timeList = [];

  _setDataType() async {
    setState(() {
      if (dataType == '1000') {
        dataType = '100';
        dataTypeText = '0.1';
      } else {
        dataType = '1000';
        dataTypeText = '1';
      }
      //dataTypeText = (dataType / 1000).toString();
    });
  }

  Future<void> _getContactData() async {
    // 记录开始时间
    var startDateTime = DateTime.now();

    // 循环调用 1000 次
    for (int i = 0; i < invokeCount; i++) {
      contactListModel = await ContactsMessageChannel.getContacts(dataType);
    }

    // 记录结束时间
    var endDateTime = DateTime.now();
    // 计算消耗的毫秒数
    var totalMilliseconds = endDateTime
        .difference(startDateTime)
        .inMilliseconds;

    getCount++;

    timeList.add("第 $getCount 次读取总耗时=$totalMilliseconds 毫秒");

    // 更新界面
    setState(() {});
  }

  Future<void> _getSetContactData() async {
    // 记录开始时间
    var startDateTime = DateTime.now();

    // 先从Java层读取 1KB 联系人，然后序列为JSON后在Java层还原
    for (int i = 0; i < invokeCount; i++) {
      contactListModel = await ContactsMessageChannel.getContacts(dataType);
      await ContactsMessageChannel.setContacts(contactListModel.toJson(), dataType);
    }

    // 记录结束时间
    var endDateTime = DateTime.now();
    // 计算消耗的毫秒数
    var totalMilliseconds = endDateTime
        .difference(startDateTime)
        .inMilliseconds;

    getSetCount++;

    timeList.add("第 $getSetCount 次读取+写入总耗时=$totalMilliseconds 毫秒");

    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme
            .of(context)
            .colorScheme
            .inversePrimary,
        title: const Text('test flutter message channel'),
      ),
      body: Flex(
        direction: Axis.horizontal,
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
          Flexible(
            flex: 1,
            child: BuildTimeListWidget(timeList),
          ),
          Flexible(
            flex: 1,
            child: contactListModel.contactList.isEmpty
                ? const Center(child: Text('no data'))
                : BuildContactListWidget(contactListModel.contactList),
          ),
          Flexible(
            flex: 1,
            child: ListView(
              children: <Widget>[
                Container(height: 10),
                GestureDetector(
                  behavior: HitTestBehavior.opaque,
                  child: Text('数据长度约 $dataTypeText KB'),
                  onTap: () {
                    _setDataType();
                  },
                ),
                Container(height: 10),
                const Text('循环执行 1000 次'),
                Container(height: 15),
                ElevatedButton(onPressed: _getContactData,
                  child: const Text('读取原生对象数据'),
                ),
                ElevatedButton(onPressed: _getSetContactData,
                  child: const Text('读取并写回原生对象'),
                ),
              ],
            ),
          ),
        ],
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

class BuildContactListWidget extends StatelessWidget {
  final List<ContactDetails> contactList;

  const BuildContactListWidget(this.contactList, {super.key});

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      padding: const EdgeInsets.all(1),
      itemCount: contactList.length,
      itemBuilder: (context, index) {
        return ListTile(
          title: Text(contactList[index].name, style: const TextStyle(fontSize: 12),),
          subtitle: Text(contactList[index].phone, style: const TextStyle(fontSize: 12),),
        );
      },
    );
  }
}

class BuildTimeListWidget extends StatelessWidget {
  final List<String> timeList;

  const BuildTimeListWidget(this.timeList, {super.key});

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      padding: const EdgeInsets.all(2),
      itemCount: timeList.length,
      itemBuilder: (context, index) {
        return ListTile(
            title: Text(style: const TextStyle(fontSize: 12), timeList[index])
        );
      },
    );
  }
}
